/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.bff.designtime.generator.core.rtgen.dataconverter.method;

import com.fasterxml.jackson.databind.JsonSerializer;
import com.inspur.edp.bff.designtime.generator.core.VmCoreGenContext;
import com.inspur.edp.caf.generator.baseInfo.ParameterInfo;
import com.inspur.edp.caf.generator.baseInfo.TypeInfo;
import com.inspur.edp.caf.generator.method.ClassMethodGenerator;
import com.inspur.edp.caf.generator.utils.ExpressionUtils;
import com.inspur.edp.cef.api.message.CefException;
import com.inspur.edp.cef.entity.entity.ICefData;
import com.inspur.edp.cef.gencommon.MediateType;
import com.inspur.edp.cef.generator.overall.GeneratorUtil;
import org.eclipse.jdt.core.dom.*;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class JsonSerializerGenerator extends ClassMethodGenerator {
    private VmCoreGenContext nodeDataSerGenContext;
    private HashMap<String, MediateType> entityMediateTypes;
    private HashMap<String, MediateType> dataMediateTypes;

    public JsonSerializerGenerator(VmCoreGenContext nodeDataSerGenContext) {
        this.nodeDataSerGenContext = nodeDataSerGenContext;
        this.entityMediateTypes = this.nodeDataSerGenContext.getEntityMediateTypes();
        this.dataMediateTypes = this.nodeDataSerGenContext.getEntityDataMediateTypes();
    }

    @Override
    protected Block buildMethodBody() {
        Block block = ast.newBlock();
        buildIfStatements(block);
        buildThowExceptionStatement(block);
        return block;
    }

    private void buildThowExceptionStatement(Block block) {
        addImport(CefException.class.getTypeName());
        MethodInvocation methodInvocation = ast.newMethodInvocation();
        methodInvocation.setExpression(ast.newSimpleName(methodParam()));
        methodInvocation.setName(ast.newSimpleName("getClass"));
        ThrowStatement throwStatement = GeneratorUtil.getThrowStatement(ast,"获取序列化器失败 ClassName:",methodInvocation,true);
//        ClassInstanceCreation classInstanceCreation = ast.newClassInstanceCreation();
//        classInstanceCreation.setType(new TypeInfo(RuntimeException.class).getType(ast));
//        InfixExpression infixExpression = ast.newInfixExpression();
//        infixExpression.setLeftOperand(ExpressionUtils.getStringLiteral(ast, "获取序列化器失败 ClassName:"));
//        infixExpression.setOperator(InfixExpression.Operator.PLUS);

//        infixExpression.setRightOperand(methodInvocation);
//        classInstanceCreation.arguments().add(infixExpression);
//        throwStatement.setExpression(classInstanceCreation);
        block.statements().add(throwStatement);
    }

    private void buildIfStatements(Block block) {
        if (dataMediateTypes == null || dataMediateTypes.isEmpty()) {
            return;
        }
        for (Map.Entry<String, MediateType> nodeData : dataMediateTypes.entrySet()) {
            if (entityMediateTypes.containsKey(nodeData.getKey())) {
                IfStatement returnStatement = getIfStatement(nodeData.getKey(), nodeData.getValue());
                block.statements().add(returnStatement);
            }
        }
    }

    private IfStatement getIfStatement(String key, MediateType objectType) {
        IfStatement ifStatement = ast.newIfStatement();
        InstanceofExpression instance = ast.newInstanceofExpression();
        instance.setLeftOperand(ast.newSimpleName(methodParam()));
        instance.setRightOperand(ast.newSimpleType(ast.newName(objectType.getClassName())));
        ifStatement.setExpression(instance);
        setThenStatement(ifStatement, key);
        return ifStatement;
    }

    private void setThenStatement(IfStatement ifStatement, String key) {
        Block block = ast.newBlock();
        ReturnStatement ifBodyReturnStatement = ast.newReturnStatement();
        MethodInvocation convertorMethodInvocation = ast.newMethodInvocation();
        convertorMethodInvocation.setName(ast.newSimpleName("getEntitySerConvertor"));
        MethodInvocation resourceInfoMethodInvocation = ast.newMethodInvocation();
        resourceInfoMethodInvocation.setName(ast.newSimpleName("getResourceInfo"));
        resourceInfoMethodInvocation.setExpression(ast.newSimpleName(entityMediateTypes.get(key).getClassName()));
        convertorMethodInvocation.setExpression(resourceInfoMethodInvocation);
        ifBodyReturnStatement.setExpression(convertorMethodInvocation);
        block.statements().add(ifBodyReturnStatement);
        ifStatement.setThenStatement(block);
    }

    @Override
    protected boolean getIsOverride() {
        return true;
    }

    @Override
    protected ArrayList<Modifier.ModifierKeyword> getAccessModifiers() {
        return new ArrayList<Modifier.ModifierKeyword>(Arrays.asList(new Modifier.ModifierKeyword[] {Modifier.ModifierKeyword.PROTECTED_KEYWORD}));
    }

    @Override
    protected String getMethodName() {
        return "getResourceInfo";
    }

    @Override
    protected ArrayList<ParameterInfo> getParameterCollection() {
        ParameterInfo parameterInfo = new ParameterInfo();
        parameterInfo.setParamType(new TypeInfo(ICefData.class));
        parameterInfo.setParamName(methodParam());
        return new ArrayList<ParameterInfo>(Arrays.asList(new ParameterInfo[] {parameterInfo}));
    }

    private String methodParam() {
        return "value";
    }

    @Override
    protected TypeInfo getReturnType() {
        TypeInfo result = new TypeInfo(JsonSerializer.class);
        result.setIsParameterizedType(true);
        result.setArguments(new ArrayList<TypeInfo>(
            Arrays.asList(new TypeInfo[]{new TypeInfo(ICefData.class)})));
        addImport(ICefData.class.getTypeName());
        return result;
    }
}
